package org.mathcloud.math.io.mml.content.generic;

import java.util.List;
import org.apache.log4j.Logger;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.mathcloud.math.core.common.factory.QuantityObjectFactory;
import org.mathcloud.math.core.common.quantity.ComplexMatrix;
import org.mathcloud.math.core.common.quantity.ComplexNumber;
import org.mathcloud.math.core.common.quantity.MatrixObject;
import org.mathcloud.math.core.common.quantity.QuantityObject;
import org.mathcloud.math.core.common.quantity.RealMatrix;
import org.mathcloud.math.core.common.quantity.RealNumber;
import org.mathcloud.math.core.common.signature.QuantityObjectSignature;
import org.mathcloud.math.core.generic.signature.GenericQuantityObjectSignature;
import org.mathcloud.math.io.mml.content.common.CNElementTranslator;
import org.mathcloud.math.io.mml.content.common.MatrixElementTranslator;
import org.mathcloud.math.io.utility.generic.GenericXMLUtility;


public class GenericMatrixElementTranslator extends GenericElementTranslator
		implements MatrixElementTranslator
{

	public GenericMatrixElementTranslator()
	{
		resultObject = null;
	}
	
	@Override
	public void translate()
	{
		if ((requestElement!=null)&&(objectFactory!=null))
		{
			QuantityObjectSignature sign = getMatrixSignature(requestElement);		
	    MatrixObject res = (MatrixObject) objectFactory.newInstance(sign);
	    CNElementTranslator cntr = new GenericCNElementTranslator();
	    cntr.setFactory(objectFactory);	    
	    @SuppressWarnings("rawtypes")
			List rows = requestElement.getChildren("matrixrow", requestElement.getNamespace());
	    QuantityObject cnq;
      for (int i=0; i<sign.getDimensions()[0]; i++)
      {
        @SuppressWarnings("rawtypes")
				List cols = ((Element)rows.get(i)).getChildren("cn",requestElement.getNamespace());                        
        for (int j=0; j<sign.getDimensions()[1]; j++)
        {
        	cntr.setRequestElement((Element) cols.get(j));
        	cntr.translate();
        	cnq = cntr.getResultObject();        
        	if (!res.getSignature().isComplex())
        	{
        		if (cnq.getSignature().isRealNumberSignature())
        			((RealMatrix)res).setMatrixElement((RealNumber)cnq,i,j);
        	}        		
        	else
        	{
        		if (cnq.getSignature().isRealNumberSignature())
        			((ComplexMatrix)res).setMatrixElement((RealNumber)cnq,i,j);
        		else if (cnq.getSignature().isComplexNumberSignature())
        			((ComplexMatrix)res).setMatrixElement((ComplexNumber)cnq,i,j);
        	}	        		
        }          
      }
      resultObject = res;
		}
	}
	
	
	@Override
	public boolean validateRequest()
	{
		return false;
	}

	@Override
	public QuantityObjectFactory getFactory()
	{
		return objectFactory;
	}

	@Override
	public void setFactory(QuantityObjectFactory arg0)
	{
		objectFactory = arg0;
	}

	@Override
	public MatrixObject getResultObject()
	{
		return resultObject;
	}
	
	@Override
	public Element getMathMLContent(QuantityObject in)
	{
    if (in==null)
      return null;
    else if (!in.getSignature().isMatrix())
    	return null;
    else
    {
      resultObject = null;
    	Element out = new Element("matrix", Namespace.getNamespace(prefix,namespaceURI));
      Element row;
      GenericCNElementTranslator cnEl = new GenericCNElementTranslator();
      QuantityObject matrixEl;
      
      for (int i=0;i<((MatrixObject)in).getNumberOfRows();i++)
      {
        row = new Element("matrixrow",out.getNamespace());
        for (int j=0;j<((MatrixObject)in).getNumberOfCols();j++)
        {
          matrixEl = ((MatrixObject)in).getMatrixElement(i,j);
          if (matrixEl.getSignature().isRealNumberSignature())
            row.addContent(cnEl.getMMLContent((RealNumber)matrixEl, null));
          else if (matrixEl.getSignature().isComplexNumberSignature())
            row.addContent(cnEl.getMMLContent((ComplexNumber) matrixEl,"complex-cartesian"));
        }
        out.addContent(row);
      }
      return out;
    }
	}
	
	public QuantityObjectSignature getMatrixSignature(Element el)
	{
		try
		{
			GenericQuantityObjectSignature res = (GenericQuantityObjectSignature) GenericQuantityObjectSignature.getRealMatrixSignature();
			int rows = el.getChildren().size();
			int cols = el.getChild("matrixrow", el.getNamespace()).getChildren().size();
			res.setDimensions(new int[]{rows,cols});
			if (GenericXMLUtility.contains(el, ".//mml:cn[@type='complex-cartesian' or @type='complex-polar']", null))
				res.setComplex(true);
			return res;
		} catch (JDOMException e)
		{
			log.error(e);
			return null;
		}
	}
	
	private MatrixObject resultObject;
	private QuantityObjectFactory objectFactory;
	private static final Logger log = Logger.getLogger(GenericMatrixElementTranslator.class);
}
